package com.salary.app;

import com.salary.constants.FileNameConstants;
import com.salary.model.SalesRecord;
import com.salary.model.SalaryResult;
import com.salary.model.SalesInfo;
import com.salary.model.CoefficientEntry; // 新增导入
import com.salary.utils.ExcelUtils;
import com.salary.utils.ExcelValidator;
import com.salary.utils.ExcelWriter;
import com.salary.utils.reader.CoefficientDataReader;
import com.salary.utils.reader.SalesDataReader;
import com.salary.utils.reader.SalesInfoReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;

/**
 * 工资计算器应用主类
 */
public class SalaryCalculatorApp extends JFrame {
    private static final Logger logger = LoggerFactory.getLogger(SalaryCalculatorApp.class);
    
    private JPanel contentPane;
    private JTextField txtFilePath = new JTextField();
    private JTextField txtSalaryInfoPath = new JTextField();
    private JTextField txtOutputTemplatePath = new JTextField();
    private JTextField txtTaxFilePath = new JTextField();
    private JTextField txtSocialInsuranceFilePath = new JTextField();
    private JTextField txtMonthlyDeductionFilePath = new JTextField();
    private JTextField txtProcessGroupPath = new JTextField();
    private JTextField txtAttendanceFilePath = new JTextField();
    private JTextField txtAssessmentScoreFilePath = new JTextField();
    private JTextField txtUtilityRentFilePath = new JTextField();
    private JTextField txtCoefficientTablePath = new JTextField(); // 新增：系数表路径
    private JButton btnCalculate;
    private JButton btnExport;
    private JButton btnExportDetailed;
    private JLabel lblStatus;
    
    private List<SalesRecord> salesRecords;
    private List<SalaryResult> salaryResults;
    private SalesInfo salesInfo;
    private String outputTemplatePath;
    private String taxFilePath;
    private String socialInsuranceFilePath;
    private String monthlyDeductionFilePath;
    private String processingGroupFilePath;
    private String attendanceFilePath;
    private String assessmentScoreFilePath;
    private String utilityRentFilePath;
    private String coefficientTablePath; // 新增：系数表路径
    private List<CoefficientEntry> coefficientEntries; // 新增：存储系数表数据

    // 添加一个变量，记住上一次打开的目录
    private File lastDirectory = null;

    /**
     * 启动应用程序
     */
    public static void main(String[] args) {
        try {
            // 设置本地系统外观
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            logger.error("设置UI外观失败: " + e.getMessage(), e);
        }
        
        EventQueue.invokeLater(() -> {
            try {
                SalaryCalculatorApp frame = new SalaryCalculatorApp();
                frame.setVisible(true);
            } catch (Exception e) {
                logger.error("启动应用程序失败: " + e.getMessage(), e);
            }
        });
    }

    /**
     * 创建应用程序
     */
    public SalaryCalculatorApp() {
        setTitle("工资计算器");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 800, 600);
        
        // 创建菜单栏
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);
        
        JMenu mnFile = new JMenu("文件");
        menuBar.add(mnFile);
        
        JMenuItem mntmExit = new JMenuItem("退出");
        mntmExit.addActionListener(e -> System.exit(0));
        mnFile.add(mntmExit);
        
        JMenu mnHelp = new JMenu("帮助");
        menuBar.add(mnHelp);
        
        JMenuItem mntmAbout = new JMenuItem("关于");
        mntmAbout.addActionListener(e -> JOptionPane.showMessageDialog(SalaryCalculatorApp.this,
                "工资计算器 v1.0\n© 2023 版权所有", "关于", JOptionPane.INFORMATION_MESSAGE));
        mnHelp.add(mntmAbout);
        
        // 创建主内容面板
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);
        
        // 创建顶部面板（文件选择和按钮）
        JPanel topPanel = new JPanel();
        contentPane.add(topPanel, BorderLayout.NORTH);
        topPanel.setLayout(new BorderLayout(0, 0));
        
        // 添加一键导入多文件的面板
        JPanel batchImportPanel = new JPanel();
        topPanel.add(batchImportPanel, BorderLayout.NORTH);
        batchImportPanel.setLayout(new BorderLayout(0, 0));
        
        JButton btnBatchImport = new JButton("一键导入多个表格文件");
        btnBatchImport.setFont(new Font("宋体", Font.BOLD, 16));
        btnBatchImport.setForeground(new Color(0, 102, 204));
        btnBatchImport.setBackground(new Color(240, 255, 240));  // 淡绿色背景
        btnBatchImport.setPreferredSize(new Dimension(200, 50));
        btnBatchImport.setIcon(UIManager.getIcon("FileView.directoryIcon"));  // 添加文件夹图标
        btnBatchImport.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                importAllFiles();
            }
        });
        batchImportPanel.add(btnBatchImport, BorderLayout.CENTER);

        
        // 添加说明面板
        JPanel infoPanel = new JPanel();
        infoPanel.setBorder(BorderFactory.createTitledBorder(""));
        infoPanel.setLayout(new GridLayout(9, 1));
        topPanel.add(infoPanel, BorderLayout.CENTER);
        
        // 添加各个文件类型的说明
        infoPanel.add(createFileInfoPanel(FileNameConstants.SALES_RECORD, txtFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.SALES_INFO, txtSalaryInfoPath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.OUTPUT_TEMPLATE, txtOutputTemplatePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.TAX_DATA, txtTaxFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.SOCIAL_INSURANCE, txtSocialInsuranceFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.MONTHLY_DEDUCTION, txtMonthlyDeductionFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.PROCESSING_GROUP, txtProcessGroupPath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.ATTENDANCE_DATA, txtAttendanceFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.ASSESSMENT_SCORE, txtAssessmentScoreFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.UTILITY_RENT_DATA, txtUtilityRentFilePath, "", true));
        infoPanel.add(createFileInfoPanel(FileNameConstants.COEFFICIENT_DATA, txtCoefficientTablePath, "", true)); // 新增
        
        // 添加导入状态面板
        JPanel importStatusPanel = new JPanel();
        importStatusPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        importStatusPanel.setBorder(BorderFactory.createTitledBorder("导入状态"));
        
        // 添加必需文件标签
        JLabel requiredLabel = new JLabel("必需文件: 出库列表、业务员工资资料、输出模板、个税表、社保表、扣款表、加工组、考勤表、考核得分、水电租表、系数表"); // 修改
        requiredLabel.setForeground(Color.RED);
        requiredLabel.setFont(new Font("宋体", Font.BOLD, 12));
        importStatusPanel.add(requiredLabel);
        
        // 将导入状态面板添加到顶部面板
        topPanel.add(importStatusPanel, BorderLayout.SOUTH);
        
        // 操作按钮面板
        JPanel buttonPanel = new JPanel();
        topPanel.add(buttonPanel, BorderLayout.SOUTH);
        
        btnCalculate = new JButton("计算工资");
        btnCalculate.setEnabled(false);
        btnCalculate.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                calculateSalary();
            }
        });
        buttonPanel.add(btnCalculate);
        
        btnExport = new JButton("导出工资表到模板");
        btnExport.setEnabled(false);
        btnExport.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                exportSalaryResults();
            }
        });
        buttonPanel.add(btnExport);
        
        btnExportDetailed = new JButton("导出业务员提成明细");
        btnExportDetailed.setEnabled(false);
        btnExportDetailed.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                exportDetailedCommission();
            }
        });
        buttonPanel.add(btnExportDetailed);
        
        // 添加中心信息面板
        JPanel infoContentPanel = new JPanel();
        infoContentPanel.setLayout(new BorderLayout());
        
        // 创建底部状态栏
        lblStatus = new JLabel("请导入必需的表格文件（所有10种表格文件都是计算工资的必要文件）"); // 修改
        lblStatus.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
        contentPane.add(lblStatus, BorderLayout.SOUTH);
        
        // 设置窗口在屏幕中央
        setLocationRelativeTo(null);
    }
    
    /**
     * 创建文件信息面板
     */
    private JPanel createFileInfoPanel(String label, JTextField textField, String description, boolean isRequired) {
        // 使用GridBagLayout更精确地控制布局和对齐
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        
        // 创建标签
        JLabel lblTitle = new JLabel(label + "：");
        if (isRequired) {
            lblTitle.setForeground(Color.RED);
            lblTitle.setFont(new Font("宋体", Font.BOLD, 12));
        }
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.EAST;
        gbc.insets = new Insets(0, 0, 0, 2);
        panel.add(lblTitle, gbc);
        
        // 创建圆形问号帮助按钮
        JButton helpButton = createHelpButton();
        helpButton.addActionListener(e -> showFileHelpInfo(label));
        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.insets = new Insets(0, 0, 0, 5);
        panel.add(helpButton, gbc);
        
        // 添加文本字段
        textField.setEditable(false);
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(0, 0, 0, 5);
        panel.add(textField, gbc);
        
        // 添加修改按钮
        JButton btnModify = new JButton("修改");
        btnModify.addActionListener(e -> {
            importSpecificFile(label, textField);
        });
        gbc.gridx = 3;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.fill = GridBagConstraints.NONE;
        gbc.insets = new Insets(0, 0, 0, 0);
        panel.add(btnModify, gbc);
        
        return panel;
    }
    
    /**
     * 创建圆形问号帮助按钮
     */
    private JButton createHelpButton() {
        JButton helpButton = new JButton("?");
        helpButton.setFont(new Font("Arial", Font.BOLD, 10));
        helpButton.setForeground(Color.BLACK);
//        helpButton.setBackground(new Color(65, 105, 225)); // 皇家蓝
        helpButton.setFocusPainted(false);
        helpButton.setBorderPainted(false);
        helpButton.setMargin(new Insets(0, 0, 0, 0));
        helpButton.setPreferredSize(new Dimension(16, 16));
        helpButton.setToolTipText("点击查看表格帮助信息");
        
        // 设置圆形外观
        helpButton.setUI(new BasicButtonUI() {
            @Override
            public void paint(Graphics g, JComponent c) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                
                AbstractButton b = (AbstractButton) c;
                ButtonModel model = b.getModel();
                
                if (model.isPressed()) {
                    g2d.setColor(helpButton.getBackground().darker());
                } else if (model.isRollover()) {
                    g2d.setColor(helpButton.getBackground().brighter());
                } else {
                    g2d.setColor(helpButton.getBackground());
                }
                
                g2d.fillOval(0, 0, c.getWidth() - 1, c.getHeight() - 1);
                
                // 添加边框
                g2d.setColor(new Color(50, 80, 170));
                g2d.setStroke(new BasicStroke(1.0f));
                g2d.drawOval(0, 0, c.getWidth() - 1, c.getHeight() - 1);
                
                FontMetrics fm = g2d.getFontMetrics();
                Rectangle textRect = new Rectangle(0, 0, c.getWidth(), c.getHeight());
                String text = b.getText();
                
                int x = (textRect.width - fm.stringWidth(text)) / 2;
                int y = (textRect.height - fm.getHeight()) / 2 + fm.getAscent();
                
                g2d.setColor(helpButton.getForeground());
                g2d.setFont(helpButton.getFont());
                g2d.drawString(text, x, y);
                
                g2d.dispose();
            }
        });
        
        return helpButton;
    }
    
    /**
     * 显示文件帮助信息
     */
    private void showFileHelpInfo(String fileType) {
        String title = "表格帮助信息";
        String message = "";
        
        if (fileType.contains(FileNameConstants.SALES_RECORD)) {
            title = "出库列表帮助";
            message = "【文件格式】\n" +
                    "- 必须包含名为'数据源'的工作表\n" +
                    "- 数据源表需要包含列：业务员、数量、吨纸毛利等\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "计算业务员提成的基础数据，为工资计算的主要数据源\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'出库列表.xlsx'或'出库列表.xls'";
        } else if (fileType.contains(FileNameConstants.SALES_INFO)) {
            title = "业务员工资资料帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、收承兑吨数等\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "包含收承兑吨数等辅助计算参数，用于计算业务员工资的辅助数据表\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'业务员工资资料.xlsx'或'业务员工资资料.xls'";
        } else if (fileType.contains(FileNameConstants.OUTPUT_TEMPLATE)) {
            title = "输出模板帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中需包含工资表模板工作表\n" +
                    "- 模板表应有预设格式和公式\n" +
                    "- 必须包含表头行和适当的单元格格式\n\n" +
                    "【用途】\n" +
                    "用于导出最终工资表的模板文件，系统会将计算结果填入该模板\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'输出模板.xlsx'或'输出模板.xls'";
        } else if (fileType.contains(FileNameConstants.TAX_DATA)) {
            title = "个税表帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、个税\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "导入每位员工的个人所得税数据，用于计算最终工资\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'个税表.xlsx'或'个税表.xls'";
        } else if (fileType.contains(FileNameConstants.SOCIAL_INSURANCE)) {
            title = "社保表帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、社保\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "导入每位员工的社会保险费数据，用于计算最终工资\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'社保表.xlsx'或'社保表.xls'";
        } else if (fileType.contains(FileNameConstants.MONTHLY_DEDUCTION)) {
            title = "扣款表帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、金额、事由\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "导入各种扣款项目数据，会在最终工资中扣除\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'扣款表.xlsx'或'扣款表.xls'";
        } else if (fileType.contains(FileNameConstants.PROCESSING_GROUP)) {
            title = "加工组帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中必须包含两个工作表：'分切组'和'卡板工'\n" +
                    "- 分切组表需包含列：姓名、数量等\n" +
                    "- 卡板工表需包含列：姓名、数量等\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "计算分切组和卡板工的工资数据，用于非业务员工资计算\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'加工组.xlsx'或'加工组.xls'";
        } else if (fileType.contains(FileNameConstants.ATTENDANCE_DATA)) {
            title = "考勤表帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、病假、带薪假、事假、旷工、迟到次数、1.5倍、2倍、3倍、实际出勤\n" +
                    "- Excel文件可以命名为任意名称\n\n" +
                    "【用途】\n" +
                    "根据员工考勤情况计算考勤系数，影响最终工资\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'考勤表.xlsx'或'考勤表.xls'";
        } else if (fileType.contains(FileNameConstants.ASSESSMENT_SCORE)) {
            title = "考核得分帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、分数\n" +
                    "- 表头应在第1-2行，数据从第3行开始\n\n" +
                    "【用途】\n" +
                    "根据员工绩效评分计算绩效系数，影响最终工资\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'考核得分.xlsx'或'考核得分.xls'";
        } else if (fileType.contains(FileNameConstants.UTILITY_RENT_DATA)) {
            title = "水电租表帮助";
            message = "【文件格式】\n" +
                    "- Excel文件中应包含主工作表\n" +
                    "- 主工作表需要包含列：姓名、水费、电费等\n" +
                    "- 表头应在第1行，数据从第2行开始\n\n" +
                    "【用途】\n" +
                    "导入水电房租数据，用于计算最终工资\n\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'水电租表.xlsx'或'水电租表.xls'";
        } else if (fileType.contains(FileNameConstants.COEFFICIENT_DATA)) { // 新增帮助信息
            title = "系数表帮助";
            message = "【文件格式】\n" +
                    "- 必须包含名为'数据源'的工作表\n" +
                    "- 数据源表需要包含列：姓名、系数\n" +
                    "- 表头应在第1行，数据从第2行开始\n\\n" +
                    "【用途】\n" +
                    "包含员工的奖金计算系数\\n\\n" +
                    "【文件名要求】\n" +
                    "文件名必须是'系数表.xlsx'或'系数表.xls'";
        }
        
        // 创建美观的帮助对话框
        JTextArea textArea = new JTextArea(message);
        textArea.setEditable(false);
        textArea.setWrapStyleWord(true);
        textArea.setLineWrap(true);
        textArea.setFont(new Font("宋体", Font.PLAIN, 14));
        textArea.setMargin(new Insets(10, 10, 10, 10));
        textArea.setBackground(new Color(250, 250, 250));
        
        // 为标题行设置不同的样式
        JTextPane textPane = new JTextPane();
        textPane.setEditable(false);
        textPane.setBackground(new Color(250, 250, 250));
        textPane.setMargin(new Insets(10, 10, 10, 10));
        
        // 设置样式
        javax.swing.text.StyledDocument doc = textPane.getStyledDocument();
        javax.swing.text.Style defaultStyle = javax.swing.text.StyleContext.getDefaultStyleContext().getStyle(javax.swing.text.StyleContext.DEFAULT_STYLE);
        javax.swing.text.Style titleStyle = doc.addStyle("TitleStyle", defaultStyle);
        javax.swing.text.StyleConstants.setFontSize(titleStyle, 14);
        javax.swing.text.StyleConstants.setBold(titleStyle, true);
        javax.swing.text.StyleConstants.setForeground(titleStyle, new Color(65, 105, 225));
        
        javax.swing.text.Style contentStyle = doc.addStyle("ContentStyle", defaultStyle);
        javax.swing.text.StyleConstants.setFontSize(contentStyle, 13);
        
        try {
            String[] lines = message.split("\n");
            for (String line : lines) {
                if (line.startsWith("【") && line.endsWith("】")) {
                    doc.insertString(doc.getLength(), line + "\n", titleStyle);
                } else {
                    doc.insertString(doc.getLength(), line + "\n", contentStyle);
                }
            }
        } catch (javax.swing.text.BadLocationException e) {
            e.printStackTrace();
        }
        
        JScrollPane scrollPane = new JScrollPane(textPane);
        scrollPane.setPreferredSize(new Dimension(400, 300));
        
        // 显示对话框
        JOptionPane.showMessageDialog(this, scrollPane, title, JOptionPane.INFORMATION_MESSAGE);
    }
    
    /**
     * 导入特定类型的文件
     */
    private void importSpecificFile(String fileType, JTextField textField) {
        JFileChooser fileChooser = new JFileChooser();
        // 设置初始目录为上一次打开的目录或当前目录
        if (lastDirectory != null && lastDirectory.exists()) {
            fileChooser.setCurrentDirectory(lastDirectory);
        }
        
        fileChooser.setDialogTitle("选择" + fileType + "文件");
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        
        // 设置文件过滤器，只显示Excel文件
        fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
            public boolean accept(File f) {
                return f.isDirectory() || f.getName().toLowerCase().endsWith(".xlsx") || f.getName().toLowerCase().endsWith(".xls");
            }
            public String getDescription() {
                return "Excel文件 (*.xlsx, *.xls)";
            }
        });
        
        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            
            // 记住当前打开文件的目录
            lastDirectory = selectedFile.getParentFile();
            
            String filePath = selectedFile.getAbsolutePath();
            String fileName = selectedFile.getName().toLowerCase();
            boolean isValid = false;
            
            // 添加文件名检查提示
            String expectedFileName = "";
            if (fileType.contains("出库列表")) {
                expectedFileName = "出库列表";
            } else if (fileType.contains("业务员工资资料")) {
                expectedFileName = "业务员工资资料";
            } else if (fileType.contains("输出模板")) {
                expectedFileName = "输出模板";
            } else if (fileType.contains("个税表")) {
                expectedFileName = "个税表";
            } else if (fileType.contains("社保表")) {
                expectedFileName = "社保表";
            } else if (fileType.contains("扣款表")) {
                expectedFileName = "扣款表";
            } else if (fileType.contains("加工组")) {
                expectedFileName = "加工组";
            } else if (fileType.contains("考勤表")) {
                expectedFileName = "考勤表";
            } else if (fileType.contains("考核得分")) {
                expectedFileName = "考核得分";
            } else if (fileType.contains("水电租表")) {
                expectedFileName = "水电租表";
            } else if (fileType.contains("系数表")) { // 新增
                expectedFileName = "系数表";
            }
            
            // 检查文件名是否符合预期
            if (!fileName.equals(expectedFileName + ".xlsx") && !fileName.equals(expectedFileName + ".xls")) {
                int option = JOptionPane.showConfirmDialog(this,
                        "警告：文件名不符合规范，应为\"" + expectedFileName + ".xlsx\"或\"" + expectedFileName + ".xls\"，当前文件名：" + fileName + "\n是否继续导入？",
                        "文件名不规范", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                
                if (option != JOptionPane.YES_OPTION) {
                    return; // 用户选择取消导入
                }
            }
            
            try {
                // 根据文件类型进行验证
                if (fileType.contains("出库列表")) {
                    isValid = ExcelValidator.validateSalaryDataTable(filePath);
                    if (isValid) {

                        List<SalesRecord> records = new SalesDataReader().readData(filePath);
                        if (records != null && !records.isEmpty()) {
                            salesRecords = records;
                            txtFilePath.setText(filePath);
                            lblStatus.setText("成功导入出库列表: " + selectedFile.getName());
                        }
                    }
                } else if (fileType.contains("业务员工资资料")) {
                    isValid = ExcelValidator.validateSalaryInfoTable(filePath);
                    if (isValid) {
                        SalesInfo info = new SalesInfoReader().readData(filePath);
                        if (info != null) {
                            salesInfo = info;
                            txtSalaryInfoPath.setText(filePath);
                            lblStatus.setText("成功导入业务员工资资料: " + selectedFile.getName());
                        }
                    }
                } else if (fileType.contains("输出模板")) {
                    isValid = ExcelValidator.validateOutputTemplate(filePath);
                    if (isValid) {
                        outputTemplatePath = filePath;
                        txtOutputTemplatePath.setText(filePath);
                        lblStatus.setText("成功导入输出模板: " + selectedFile.getName());
                    }
                } else if (fileType.contains("个税表")) {
                    isValid = ExcelValidator.validateTaxTable(filePath);
                    if (isValid) {
                        taxFilePath = filePath;
                        txtTaxFilePath.setText(filePath);
                        lblStatus.setText("成功导入个税表: " + selectedFile.getName());
                    }
                } else if (fileType.contains("社保表")) {
                    isValid = ExcelValidator.validateSocialInsuranceTable(filePath);
                    if (isValid) {
                        socialInsuranceFilePath = filePath;
                        txtSocialInsuranceFilePath.setText(filePath);
                        lblStatus.setText("成功导入社保表: " + selectedFile.getName());
                    }
                } else if (fileType.contains("扣款表")) {
                    isValid = ExcelValidator.validateMonthlyDeductionTable(filePath);
                    if (isValid) {
                        monthlyDeductionFilePath = filePath;
                        txtMonthlyDeductionFilePath.setText(filePath);
                        lblStatus.setText("成功导入扣款表: " + selectedFile.getName());
                    }
                } else if (fileType.contains("加工组")) {
                    isValid = ExcelValidator.validateProcessingGroupTable(filePath);
                    if (isValid) {
                        processingGroupFilePath = filePath;
                        txtProcessGroupPath.setText(filePath);
                        lblStatus.setText("成功导入加工组: " + selectedFile.getName());
                    }
                } else if (fileType.contains("考勤表")) {
                    isValid = ExcelValidator.validateAttendanceTable(filePath);
                    if (isValid) {
                        attendanceFilePath = filePath;
                        txtAttendanceFilePath.setText(filePath);
                        lblStatus.setText("成功导入考勤表: " + selectedFile.getName());
                    }
                } else if (fileType.contains("考核得分")) {
                    isValid = ExcelValidator.validateAssessmentScoreTable(filePath);
                    if (isValid) {
                        assessmentScoreFilePath = filePath;
                        txtAssessmentScoreFilePath.setText(filePath);
                        lblStatus.setText("成功导入考核得分: " + selectedFile.getName());
                    }
                } else if (fileType.contains("水电租表")) {
                    isValid = ExcelValidator.validateUtilityRentTable(filePath);
                    if (isValid) {
                        utilityRentFilePath = filePath;
                        txtUtilityRentFilePath.setText(filePath);
                        lblStatus.setText("成功导入水电租表: " + selectedFile.getName());
                    }
                } else if (fileType.contains("系数表")) { // 新增
                    isValid = ExcelValidator.validateCoefficientTable(filePath); // 稍后在ExcelUtils中实现
                    if (isValid) {
                        List<CoefficientEntry> entries = new CoefficientDataReader().readData(filePath); // 稍后在ExcelUtils中实现
                        if (entries != null) { // 假设读取成功
                            coefficientEntries = entries; // 假设有一个成员变量 coefficientEntries
                            coefficientTablePath = filePath;
                            txtCoefficientTablePath.setText(filePath);
                            lblStatus.setText("成功导入系数表: " + selectedFile.getName());
                        }
                    }
                }
                
                if (!isValid) {
                    JOptionPane.showMessageDialog(this, 
                        "导入的文件格式不符合" + fileType + "的要求，请检查后重试。", 
                        "导入失败", JOptionPane.ERROR_MESSAGE);
                }
                
                // 检查是否所有必要文件都已导入
                boolean hasAllFiles = txtFilePath.getText().length() > 0 &&
                                    txtSalaryInfoPath.getText().length() > 0 &&
                                    txtOutputTemplatePath.getText().length() > 0 &&
                                    txtTaxFilePath.getText().length() > 0 &&
                                    txtSocialInsuranceFilePath.getText().length() > 0 &&
                                    txtMonthlyDeductionFilePath.getText().length() > 0 &&
                                    txtProcessGroupPath.getText().length() > 0 &&
                                    txtAttendanceFilePath.getText().length() > 0 &&
                                    txtAssessmentScoreFilePath.getText().length() > 0 &&
                                    txtUtilityRentFilePath.getText().length() > 0 &&
                                    txtCoefficientTablePath.getText().length() > 0; // 新增
                btnCalculate.setEnabled(hasAllFiles);
                
                if (hasAllFiles) {
                    lblStatus.setText("所有必需文件导入成功，可以计算工资");
                }
                
            } catch (Exception ex) {
                logger.error("导入" + fileType + "文件失败: " + ex.getMessage(), ex);
                JOptionPane.showMessageDialog(this, 
                    "导入" + fileType + "文件失败: " + ex.getMessage(), 
                    "导入错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    
    /**
     * 计算工资
     */
    private void calculateSalary() {
        if (salesRecords == null || salesRecords.isEmpty()) {
            JOptionPane.showMessageDialog(this, "请先导入业务员出库表", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        if (salesInfo == null) {
            JOptionPane.showMessageDialog(this, "请先导入工资资料表", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        lblStatus.setText("正在计算工资...");
        
        // 使用SwingWorker在后台线程处理计算操作
        new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                // 传递工资资料信息到计算方法
                salaryResults = ExcelUtils.calculateSalary(salesRecords, salesInfo);
                return null;
            }
            
            @Override
            protected void done() {
                // 统计处理的业务员数量和收承兑总量
                int salespersonCount = salaryResults.size();
                double totalTonnage = salesInfo.getAcceptanceCollection(); // 这个salaryInfo是导入工资资料表时的，不包含总销量
                double totalDeduction = salesInfo.calculateAcceptanceDeduction(); // 同上

                // 获取销售总量（不含东莞诚昌） - 从 GlobalDataStore 获取最新的 SalaryInfo
                SalesInfo globalSalesInfo = com.salary.utils.GlobalDataStore.getSalaryInfo();
                double totalSalesQuantity = (globalSalesInfo != null) ? globalSalesInfo.getTotalSalesQuantity() : 0.0;
                
                // 特殊业务员奖金计算基数，目前与销售总量一致，但后续可能调整
                double specialBonusBaseQuantity = totalSalesQuantity; 

                lblStatus.setText(String.format("业务员工资计算完成，共%d名业务员，收承兑总吨数：%.2f吨，总扣款金额：%.2f元，销售总量（不含东莞诚昌）：%.2f吨",
                        salespersonCount, totalTonnage, totalDeduction, totalSalesQuantity));
                
                btnExport.setEnabled(true);
                btnExportDetailed.setEnabled(true);
                
                // 显示计算完成对话框，并提供导出和打开文件选项
                Object[] options = {"导出到Excel", "暂不导出"};
                int choice = JOptionPane.showOptionDialog(SalaryCalculatorApp.this,
                        String.format("工资计算完成！\n共计%d名业务员，收承兑总吨数：%.2f吨，总扣款金额：%.2f元\n销售总量（不含东莞诚昌）：%.2f吨\n特殊业务员奖金计算基数：%.2f吨\n\n是否立即导出到Excel文件？",
                                salespersonCount, totalTonnage, totalDeduction, totalSalesQuantity, specialBonusBaseQuantity), // 使用更新后的totalSalesQuantity和specialBonusBaseQuantity
                        "计算完成",
                        JOptionPane.YES_NO_OPTION,
                        JOptionPane.INFORMATION_MESSAGE,
                        null,
                        options,
                        options[0]);
                
                if (choice == 0) {
                    exportSalaryResults();
                }
            }
        }.execute();
    }
    
    /**
     * 导出工资结果
     */
    private void exportSalaryResults() {
        if (salaryResults == null || salaryResults.isEmpty()) {
            JOptionPane.showMessageDialog(this, "请先计算工资", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        // 检查是否已导入输出模板
        if (outputTemplatePath == null || outputTemplatePath.isEmpty()) {
            int option = JOptionPane.showConfirmDialog(this,
                    "未导入输出模板，是否先导入？\n（如不导入将使用默认的'输出.xlsx'模板）",
                    "未导入模板", JOptionPane.YES_NO_CANCEL_OPTION);
            
            if (option == JOptionPane.YES_OPTION) {
                JOptionPane.showMessageDialog(this, 
                        "请使用\"一键导入多个表格文件\"功能，选择包含输出模板的文件。\n" +
                        "系统将自动识别文件类型。", 
                        "导入提示", JOptionPane.INFORMATION_MESSAGE);
                importAllFiles();
                return; // 等待用户导入模板后再导出
            } else if (option == JOptionPane.CANCEL_OPTION) {
                return; // 用户取消导出
            }
            // 如果用户选择NO，则继续使用默认模板
        }
        
        // 检查是否已导入个税表和社保表等辅助文件
        boolean hasTaxFile = (taxFilePath != null && !taxFilePath.isEmpty());
        boolean hasSocialInsuranceFile = (socialInsuranceFilePath != null && !socialInsuranceFilePath.isEmpty());
        boolean hasMonthlyDeductionFile = (monthlyDeductionFilePath != null && !monthlyDeductionFilePath.isEmpty());
        boolean hasProcessingGroupFile = (processingGroupFilePath != null && !processingGroupFilePath.isEmpty());
        boolean hasAttendanceFile = (attendanceFilePath != null && !attendanceFilePath.isEmpty());
        boolean hasAssessmentScoreFile = (assessmentScoreFilePath != null && !assessmentScoreFilePath.isEmpty());
        boolean hasUtilityRentFile = (utilityRentFilePath != null && !utilityRentFilePath.isEmpty());
        boolean hasCoefficientTableFile = (coefficientTablePath != null && !coefficientTablePath.isEmpty());
        
        // 构建消息提示哪些文件将被导入
        StringBuilder importSummary = new StringBuilder("将导出工资表，并：\n");
        importSummary.append("- 写入业务员提成数据\n");
        
        // 根据是否有文件添加提示
        String taxStatus = hasTaxFile ? "✓ 导入个税数据" : "✗ 不导入个税数据（未提供文件）";
        String socialInsuranceStatus = hasSocialInsuranceFile ? "✓ 导入社保数据" : "✗ 不导入社保数据（未提供文件）";
        String monthlyDeductionStatus = hasMonthlyDeductionFile ? "✓ 导入每月扣款数据" : "✗ 不导入每月扣款数据（未提供文件）";
        String processingGroupStatus = hasProcessingGroupFile ? "✓ 导入加工组数据" : "✗ 不导入加工组数据（未提供文件）";
        String attendanceStatus = hasAttendanceFile ? "✓ 导入考勤数据" : "✗ 不导入考勤数据（未提供文件）";
        String assessmentScoreStatus = hasAssessmentScoreFile ? "✓ 导入考核得分数据" : "✗ 不导入考核得分数据（未提供文件）";
        String utilityRentStatus = hasUtilityRentFile ? "✓ 导入水电房租数据" : "✗ 不导入水电房租数据（未提供文件）";
        String coefficientTableStatus = hasCoefficientTableFile ? "✓ 导入系数表数据" : "✗ 不导入系数表数据（未提供文件）";
        
        importSummary.append("- ").append(taxStatus).append("\n");
        importSummary.append("- ").append(socialInsuranceStatus).append("\n");
        importSummary.append("- ").append(monthlyDeductionStatus).append("\n");
        importSummary.append("- ").append(processingGroupStatus).append("\n");
        importSummary.append("- ").append(attendanceStatus).append("\n");
        importSummary.append("- ").append(assessmentScoreStatus).append("\n");
        importSummary.append("- ").append(utilityRentStatus).append("\n");
        importSummary.append("- ").append(coefficientTableStatus).append("\n");
        
        importSummary.append("\n确认导出工资表？");
        
        // 询问用户确认
        int option = JOptionPane.showConfirmDialog(this,
                importSummary.toString(),
                "导出确认", JOptionPane.YES_NO_OPTION);
        
        if (option != JOptionPane.YES_OPTION) {
            return; // 用户取消导出
        }
        
        // 设置状态
        lblStatus.setText("正在导出工资表...");
        
        // 创建后台线程处理导出
        new SwingWorker<String, Void>() {
            @Override
            protected String doInBackground() throws Exception {
                // 使用用户指定的模板，并传递各种表格路径，包括水电租表路径
                return ExcelWriter.writeSalaryResultsToTemplate(salaryResults, outputTemplatePath, taxFilePath,
                        socialInsuranceFilePath, monthlyDeductionFilePath, processingGroupFilePath,
                        attendanceFilePath, assessmentScoreFilePath, utilityRentFilePath, coefficientTablePath);
            }
            
            @Override
            protected void done() {
                try {
                    String outputPath = get();
                    if (outputPath != null) {
                        lblStatus.setText("工资表导出成功，保存在：" + outputPath);
                        
                        StringBuilder message = new StringBuilder("工资表导出成功！\n");
                        message.append("已将提成数据写入到总奖金列\n");
                        if (taxFilePath != null && !taxFilePath.isEmpty()) {
                            message.append("已将个税数据写入到个税列\n");
                        }
                        if (socialInsuranceFilePath != null && !socialInsuranceFilePath.isEmpty()) {
                            message.append("已将社保数据写入到社保列\n");
                        }
                        if (monthlyDeductionFilePath != null && !monthlyDeductionFilePath.isEmpty()) {
                            message.append("已将扣款数据写入到应扣部分-其他列\n");
                        }
                        if (processingGroupFilePath != null && !processingGroupFilePath.isEmpty()) {
                            message.append("已将加工组工资数据计算并写入到总奖金列\n");
                        }
                        if (attendanceFilePath != null && !attendanceFilePath.isEmpty()) {
                            message.append("已将考勤数据计算并写入\n");
                        }
                        if (assessmentScoreFilePath != null && !assessmentScoreFilePath.isEmpty()) {
                            message.append("已应用考核得分系数调整总奖金\n");
                        }
                        if (utilityRentFilePath != null && !utilityRentFilePath.isEmpty()) {
                            message.append("已将水电房租数据写入到水电房租列\n");
                        }
                        if (coefficientTablePath != null && !coefficientTablePath.isEmpty()) {
                            message.append("已将系数表数据写入到系数表列\n");
                        }
                        message.append("文件位置：").append(outputPath);
                        
                        // 提供更多的文件操作选项
                        Object[] options = {"打开文件", "打开文件夹", "关闭"};
                        int choice = JOptionPane.showOptionDialog(SalaryCalculatorApp.this, 
                                message.toString(), 
                                "导出成功", 
                                JOptionPane.DEFAULT_OPTION, 
                                JOptionPane.INFORMATION_MESSAGE,
                                null,
                                options,
                                options[0]);
                        
                        try {
                            if (choice == 0) {
                                // 打开Excel文件
                                Desktop.getDesktop().open(new File(outputPath));
                            } else if (choice == 1) {
                                // 打开文件所在目录
                                Desktop.getDesktop().open(new File(outputPath).getParentFile());
                            }
                        } catch (Exception e) {
                            logger.error("打开文件或文件夹失败: " + e.getMessage(), e);
                            JOptionPane.showMessageDialog(SalaryCalculatorApp.this,
                                    "打开文件或文件夹失败：" + e.getMessage(),
                                    "操作失败", JOptionPane.ERROR_MESSAGE);
                        }
                    } else {
                        lblStatus.setText("工资表导出失败");
                        JOptionPane.showMessageDialog(SalaryCalculatorApp.this, 
                                "工资表导出失败，请确保模板文件存在并且没有被其他程序打开", 
                                "导出失败", JOptionPane.ERROR_MESSAGE);
                    }
                } catch (Exception e) {
                    logger.error("导出结果处理失败: " + e.getMessage(), e);
                    lblStatus.setText("工资表导出失败");
                    JOptionPane.showMessageDialog(SalaryCalculatorApp.this, 
                            "工资表导出失败：" + e.getMessage(), "导出失败", JOptionPane.ERROR_MESSAGE);
                }
            }
        }.execute();
    }

    /**
     * 导出业务员详细提成数据
     */
    private void exportDetailedCommission() {
        if (salesRecords == null || salesRecords.isEmpty()) {
            JOptionPane.showMessageDialog(this, "请先导入业务员出库表并计算工资", "错误", JOptionPane.ERROR_MESSAGE);
            return;
        }
        
        lblStatus.setText("正在导出业务员提成明细...");
        
        // 使用SwingWorker在后台线程处理导出操作
        new SwingWorker<String, Void>() {
            @Override
            protected String doInBackground() throws Exception {
                return ExcelWriter.exportDetailedCommission(salesRecords);
            }
            
            @Override
            protected void done() {
                try {
                    String outputPath = get();
                    if (outputPath != null) {
                        lblStatus.setText("提成明细导出成功，保存在：" + outputPath);
                        
                        // 提供更多的文件操作选项
                        Object[] options = {"打开文件", "打开文件夹", "关闭"};
                        int choice = JOptionPane.showOptionDialog(SalaryCalculatorApp.this, 
                                "业务员提成明细导出成功！\n" +
                                "包含每行业务数据的提成明细，便于检查错误\n" +
                                "文件位置：" + outputPath, 
                                "导出成功", 
                                JOptionPane.DEFAULT_OPTION, 
                                JOptionPane.INFORMATION_MESSAGE,
                                null,
                                options,
                                options[0]);
                        
                        try {
                            if (choice == 0) {
                                // 打开Excel文件
                                Desktop.getDesktop().open(new File(outputPath));
                            } else if (choice == 1) {
                                // 打开文件所在目录
                                Desktop.getDesktop().open(new File(outputPath).getParentFile());
                            }
                        } catch (Exception e) {
                            logger.error("打开文件或文件夹失败: " + e.getMessage(), e);
                            JOptionPane.showMessageDialog(SalaryCalculatorApp.this,
                                    "打开文件或文件夹失败：" + e.getMessage(),
                                    "操作失败", JOptionPane.ERROR_MESSAGE);
                        }
                    } else {
                        lblStatus.setText("提成明细导出失败");
                        JOptionPane.showMessageDialog(SalaryCalculatorApp.this, 
                                "提成明细导出失败，请确保有足够的磁盘空间和写入权限", 
                                "导出失败", JOptionPane.ERROR_MESSAGE);
                    }
                } catch (Exception e) {
                    logger.error("导出提成明细失败: " + e.getMessage(), e);
                    lblStatus.setText("提成明细导出失败");
                    JOptionPane.showMessageDialog(SalaryCalculatorApp.this, 
                            "提成明细导出失败：" + e.getMessage(), "导出失败", JOptionPane.ERROR_MESSAGE);
                }
            }
        }.execute();
    }

    /**
     * 一键导入多个文件，自动识别文件类型并校验
     */
    private void importAllFiles() {
        JFileChooser fileChooser = new JFileChooser();
        // 设置初始目录为上一次打开的目录或当前目录
        if (lastDirectory != null && lastDirectory.exists()) {
            fileChooser.setCurrentDirectory(lastDirectory);
        }
        
        fileChooser.setDialogTitle("选择所有必需的Excel表格文件（请注意：文件名必须符合规范）");
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fileChooser.setMultiSelectionEnabled(true); // 允许多选文件
        
        // 设置文件过滤器，只显示Excel文件
        fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
            public boolean accept(File f) {
                return f.isDirectory() || f.getName().toLowerCase().endsWith(".xlsx") || f.getName().toLowerCase().endsWith(".xls");
            }
            public String getDescription() {
                return "Excel文件 (*.xlsx, *.xls)";
            }
        });
        
        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            File[] selectedFiles = fileChooser.getSelectedFiles();
            
            // 记住当前打开文件的目录
            if (selectedFiles.length > 0) {
                lastDirectory = selectedFiles[0].getParentFile();
            }
            
            // 创建处理结果列表
            final List<String> successMessages = new ArrayList<>();
            final List<String> errorMessages = new ArrayList<>();
            
            // 设置状态栏
            lblStatus.setText("正在导入和验证多个文件...");
            
            // 记录表格验证结果
            final Map<String, Map<String, Boolean>> validationResults = new HashMap<>();
            validationResults.put("出库列表", new HashMap<>());
            validationResults.put("业务员工资资料", new HashMap<>());
            validationResults.put("输出模板", new HashMap<>());
            validationResults.put("个税表", new HashMap<>());
            validationResults.put("社保表", new HashMap<>());
            validationResults.put("扣款表", new HashMap<>());
            validationResults.put("加工组", new HashMap<>());
            validationResults.put("考勤表", new HashMap<>());
            validationResults.put("考核得分", new HashMap<>());
            validationResults.put("水电租表", new HashMap<>());
            validationResults.put("系数表", new HashMap<>()); // 新增
            
            // 创建SwingWorker在后台线程处理导入和验证操作
            SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
                // 声明为类变量，使done方法可以访问
                private boolean foundSalaryData = false;
                private boolean foundSalaryInfo = false;
                private boolean foundOutputTemplate = false;
                private boolean foundTaxData = false;
                private boolean foundSocialInsurance = false;
                private boolean foundMonthlyDeduction = false;
                private boolean foundProcessingGroup = false;
                private boolean foundAttendance = false;
                private boolean foundAssessmentScore = false;
                private boolean foundUtilityRent = false;
                private boolean foundCoefficientTable = false; // 新增
                
                @Override
                protected Void doInBackground() throws Exception {
                    // 重置导入状态变量（已移至类变量声明）
                    
                    // 添加日志分隔符，帮助定位当前导入会话
                    logger.info("========================================");
                    logger.info("开始新的文件导入会话，共选择了 " + selectedFiles.length + " 个文件");
                    logger.info("========================================");
                    
                    // 遍历所有选中的文件
                    for (File file : selectedFiles) {
                        String filePath = file.getAbsolutePath();
                        String fileName = file.getName().toLowerCase();
                        
                        logger.info("处理文件: " + filePath);
                        
                        try {
                            // 尝试识别文件类型
                            boolean identified = false;
                            
                            // 根据严格的表名规则识别文件类型 - 使用精确匹配
                            // 1. 业务员出库表 - 匹配"出库列表.xlsx"或"出库列表.xls"
                            if (!foundSalaryData && (fileName.equals("出库列表.xlsx") || fileName.equals("出库列表.xls"))) {
                                // 验证并导入业务员出库表
                                try {
                                    boolean isValid = ExcelValidator.validateSalaryDataTable(filePath);
                                    validationResults.get("出库列表").put(fileName, isValid);
                                    if (isValid) {
                                        List<SalesRecord> records = new SalesDataReader().readData(filePath);
                                        if (records != null && !records.isEmpty()) {
                                            salesRecords = records;
                                            txtFilePath.setText(filePath);
                                            successMessages.add("✓ 成功导入出库列表: " + file.getName());
                                            foundSalaryData = true;
                                            identified = true;
                                            logger.info("文件 " + fileName + " 已成功识别为出库列表");
                                        } else {
                                            logger.info("文件 " + fileName + " 内容不符合出库列表格式");
                                        }
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合出库列表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("出库列表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为出库列表读取: " + e.getMessage());
                                }
                            }
                            
                            // 2. 工资资料表 - 匹配"业务员工资资料.xlsx"或"业务员工资资料.xls"
                            if (!foundSalaryInfo && (fileName.equals("业务员工资资料.xlsx") || fileName.equals("业务员工资资料.xls"))) {
                                // 读取工资资料表
                                try {
                                    boolean isValid = ExcelValidator.validateSalaryInfoTable(filePath);
                                    validationResults.get("业务员工资资料").put(fileName, isValid);
                                    if (isValid) {
                                        SalesInfo info = new SalesInfoReader().readData(filePath);
                                        if (info != null) {
                                            salesInfo = info;
                                            txtSalaryInfoPath.setText(filePath);
                                            successMessages.add("✓ 成功导入业务员工资资料: " + file.getName());
                                            foundSalaryInfo = true;
                                            identified = true;
                                            logger.info("文件 " + fileName + " 已成功识别为业务员工资资料");
                                        } else {
                                            logger.info("文件 " + fileName + " 验证通过但无法读取内容");
                                        }
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合业务员工资资料格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("业务员工资资料").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为业务员工资资料读取: " + e.getMessage());
                                }
                            }
                            
                            // 3. 输出模板表 - 匹配"输出模板.xlsx"或"输出模板.xls"
                            if (!foundOutputTemplate && (fileName.equals("输出模板.xlsx") || fileName.equals("输出模板.xls"))) {
                                // 验证并导入输出模板
                                try {
                                    boolean isValid = ExcelValidator.validateOutputTemplate(filePath);
                                    validationResults.get("输出模板").put(fileName, isValid);
                                    if (isValid) {
                                        outputTemplatePath = filePath;
                                        txtOutputTemplatePath.setText(filePath);
                                        successMessages.add("✓ 成功导入输出模板: " + file.getName());
                                        foundOutputTemplate = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为输出模板");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合输出模板格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("输出模板").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为输出模板读取: " + e.getMessage());
                                }
                            }
                            
                            // 4. 个税表 - 匹配"个税表.xlsx"或"个税表.xls"
                            if (!foundTaxData && (fileName.equals("个税表.xlsx") || fileName.equals("个税表.xls"))) {
                                // 验证并导入个税表
                                try {
                                    boolean isValid = ExcelValidator.validateTaxTable(filePath);
                                    validationResults.get("个税表").put(fileName, isValid);
                                    if (isValid) {
                                        taxFilePath = filePath;
                                        txtTaxFilePath.setText(filePath);
                                        successMessages.add("✓ 成功导入个税表: " + file.getName());
                                        foundTaxData = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为个税表");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合个税表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("个税表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为个税表读取: " + e.getMessage());
                                }
                            }
                            
                            // 5. 社保表 - 匹配"社保表.xlsx"或"社保表.xls"
                            if (!foundSocialInsurance && (fileName.equals("社保表.xlsx") || fileName.equals("社保表.xls"))) {
                                // 验证并导入社保表
                                try {
                                    boolean isValid = ExcelValidator.validateSocialInsuranceTable(filePath);
                                    validationResults.get("社保表").put(fileName, isValid);
                                    if (isValid) {
                                        socialInsuranceFilePath = filePath;
                                        txtSocialInsuranceFilePath.setText(filePath);
                                        successMessages.add("✓ 成功导入社保表: " + file.getName());
                                        foundSocialInsurance = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为社保表");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合社保表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("社保表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为社保表读取: " + e.getMessage());
                                }
                            }
                            
                            // 6. 每月扣款表 - 匹配"扣款表.xlsx"或"扣款表.xls"
                            if (!foundMonthlyDeduction && (fileName.equals("扣款表.xlsx") || fileName.equals("扣款表.xls"))) {
                                // 验证并导入每月扣款表
                                try {
                                    boolean isValid = ExcelValidator.validateMonthlyDeductionTable(filePath);
                                    validationResults.get("扣款表").put(fileName, isValid);
                                    if (isValid) {
                                        monthlyDeductionFilePath = filePath;
                                        txtMonthlyDeductionFilePath.setText(filePath);
                                        successMessages.add("✓ 成功导入扣款表: " + file.getName());
                                        foundMonthlyDeduction = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为扣款表");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合扣款表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("扣款表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为扣款表读取: " + e.getMessage());
                                }
                            }
                            
                            // 7. 加工组表格 - 匹配"加工组.xlsx"或"加工组.xls"
                            if (!foundProcessingGroup && (fileName.equals("加工组.xlsx") || fileName.equals("加工组.xls"))) {
                                // 验证并导入加工组表格
                                try {
                                    logger.info("开始验证加工组文件: " + filePath);
                                    boolean isValid = ExcelValidator.validateProcessingGroupTable(filePath);
                                    validationResults.get("加工组").put(fileName, isValid);
                                    if (isValid) {
                                        processingGroupFilePath = filePath;
                                        txtProcessGroupPath.setText(filePath);
                                        successMessages.add("✓ 成功导入加工组: " + file.getName());
                                        foundProcessingGroup = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为加工组");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合加工组格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("加工组").put(fileName, false);
                                    logger.error("无法将文件 " + fileName + " 作为加工组读取: " + e.getMessage(), e);
                                }
                            }
                            
                            // 8. 考勤表 - 匹配"考勤表.xlsx"或"考勤表.xls"
                            if (!foundAttendance && (fileName.equals("考勤表.xlsx") || fileName.equals("考勤表.xls"))) {
                                // 验证并导入考勤表
                                try {
                                    boolean isValid = ExcelValidator.validateAttendanceTable(filePath);
                                    validationResults.get("考勤表").put(fileName, isValid);
                                    if (isValid) {
                                        attendanceFilePath = filePath;
                                        txtAttendanceFilePath.setText(filePath);
                                        successMessages.add("✓ 成功导入考勤表: " + file.getName());
                                        foundAttendance = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为考勤表");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合考勤表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("考勤表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为考勤表读取: " + e.getMessage());
                                }
                            }
                            
                            // 9. 考核得分表 - 匹配"考核得分.xlsx"或"考核得分.xls"
                            if (!foundAssessmentScore && (fileName.equals("考核得分.xlsx") || fileName.equals("考核得分.xls"))) {
                                // 验证并导入考核得分表
                                try {
                                    logger.info("开始验证考核得分文件: " + filePath);
                                    boolean isValid = ExcelValidator.validateAssessmentScoreTable(filePath);
                                    validationResults.get("考核得分").put(fileName, isValid);
                                    if (isValid) {
                                        assessmentScoreFilePath = filePath;
                                        txtAssessmentScoreFilePath.setText(filePath);
                                        successMessages.add("✓ 成功导入考核得分: " + file.getName());
                                        foundAssessmentScore = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为考核得分");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合考核得分格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("考核得分").put(fileName, false);
                                    logger.error("无法将文件 " + fileName + " 作为考核得分读取: " + e.getMessage(), e);
                                }
                            }
                            
                            // 10. 水电租表 - 匹配文件名中包含"水电租"
                            if (!foundUtilityRent && fileName.contains("水电租")) {
                                // 验证并导入水电租表
                                try {
                                    boolean isValid = ExcelValidator.validateUtilityRentTable(filePath);
                                    validationResults.get("水电租表").put(fileName, isValid);
                                    if (isValid) {
                                        utilityRentFilePath = filePath;
                                        txtUtilityRentFilePath.setText(filePath);
                                        successMessages.add("✓ 成功导入水电租表: " + file.getName());
                                        foundUtilityRent = true;
                                        identified = true;
                                        logger.info("文件 " + fileName + " 已成功识别为水电租表");
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合水电租表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("水电租表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为水电租表读取: " + e.getMessage());
                                }
                            }
                            
                            // 11. 系数表 - 匹配"系数表.xlsx"或"系数表.xls" (新增)
                            if (!foundCoefficientTable && (fileName.equals("系数表.xlsx") || fileName.equals("系数表.xls"))) {
                                try {
                                    boolean isValid = ExcelValidator.validateCoefficientTable(filePath);
                                    validationResults.get("系数表").put(fileName, isValid);
                                    if (isValid) {
                                        List<CoefficientEntry> entries = new CoefficientDataReader().readData(filePath);
                                        if (entries != null) {
                                            coefficientEntries = entries; // 新增
                                            coefficientTablePath = filePath;
                                            txtCoefficientTablePath.setText(filePath);
                                            successMessages.add("✓ 成功导入系数表: " + file.getName());
                                            foundCoefficientTable = true;
                                            identified = true;
                                            logger.info("文件 " + fileName + " 已成功识别为系数表");
                                        } else {
                                            logger.info("文件 " + fileName + " 内容不符合系数表格式");
                                        }
                                    } else {
                                        logger.info("文件 " + fileName + " 不符合系数表格式");
                                    }
                                } catch (Exception e) {
                                    validationResults.get("系数表").put(fileName, false);
                                    logger.info("无法将文件 " + fileName + " 作为系数表读取: " + e.getMessage());
                                }
                            }
                            
                            // 如果通过文件名无法识别，提示用户并检查文件内容
                            if (!identified) {
                                logger.info("无法通过文件名识别文件 " + fileName + " 的类型");
                                
                                // 尝试分析文件内容，检查是否是水电租表
                                try {
                                    // 如果文件包含"数据源"工作表和"姓名"、"水费"等列，可能是水电租表
                                    if (!foundUtilityRent) {
                                        try (FileInputStream fis = new FileInputStream(filePath);
                                             Workbook wb = WorkbookFactory.create(fis)) {
                                            
                                            Sheet dataSheet = wb.getSheet("数据源");
                                            if (dataSheet != null) {
                                                // 进一步检查是否包含必要的列
                                                boolean isUtilityRent = ExcelValidator.validateUtilityRentTable(filePath);
                                                if (isUtilityRent) {
                                                    utilityRentFilePath = filePath;
                                                    txtUtilityRentFilePath.setText(filePath);
                                                    successMessages.add("✓ 成功导入水电租表(自动识别): " + file.getName());
                                                    foundUtilityRent = true;
                                                    identified = true;
                                                    logger.info("文件 " + fileName + " 已自动识别为水电租表");
                                                    continue;
                                                }
                                            }
                                        } catch (Exception e) {
                                            // 忽略此处的异常，继续尝试其他文件类型
                                        }
                                    }
                                } catch (Exception e) {
                                    // 忽略分析错误，继续检查其他可能性
                                }
                                
                                // 继续原有的未识别文件分析
                                analyzeUnidentifiedExcelFile(filePath, fileName, errorMessages);
                            }
                        } catch (Exception e) {
                            logger.error("处理文件 " + filePath + " 时出错: " + e.getMessage(), e);
                            errorMessages.add("✗ 处理文件 " + file.getName() + " 时出错: " + e.getMessage());
                        }
                    }
                    
                    // 打印验证结果汇总
                    logger.info("========================================");
                    logger.info("文件验证结果汇总:");
                    for (Map.Entry<String, Map<String, Boolean>> entry : validationResults.entrySet()) {
                        String tableType = entry.getKey();
                        Map<String, Boolean> results = entry.getValue();
                        
                        if (!results.isEmpty()) {
                            logger.info(tableType + " 验证结果:");
                            for (Map.Entry<String, Boolean> fileResult : results.entrySet()) {
                                logger.info("  文件 [" + fileResult.getKey() + "]: " + (fileResult.getValue() ? "有效" : "无效"));
                            }
                        }
                    }
                    logger.info("========================================");
                    
                    return null;
                }
                
                @Override
                protected void done() {
                    // 更新导入状态信息 - 所有文件都是必需的
                    boolean hasRequiredFiles = foundSalaryData && foundSalaryInfo && 
                                             foundOutputTemplate && foundTaxData && 
                                             foundSocialInsurance && foundMonthlyDeduction && 
                                             foundProcessingGroup && foundAttendance && 
                                             foundAssessmentScore && foundUtilityRent && 
                                             foundCoefficientTable; // 新增
                    btnCalculate.setEnabled(hasRequiredFiles);
                    
                    // 显示导入结果
                    StringBuilder resultMessage = new StringBuilder();
                    
                    // 添加强调说明
                    resultMessage.append("注意：所有文件都是计算工资的必要文件，请确保全部导入！\n\n");
                    
                    // 如果有错误，列出错误信息
                    if (!errorMessages.isEmpty()) {
                        resultMessage.append("【导入错误与警告】：\n");
                        for (String msg : errorMessages) {
                            resultMessage.append(msg).append("\n");
                        }
                        resultMessage.append("\n");
                    }
                    
                    // 列出所有文件的导入状态
                    resultMessage.append("【文件导入状态】：\n");
                    resultMessage.append(foundSalaryData ? "✓ 出库列表 - 已导入\n" : "✗ 出库列表 - 未导入 (必需)\n");
                    resultMessage.append(foundSalaryInfo ? "✓ 业务员工资资料 - 已导入\n" : "✗ 业务员工资资料 - 未导入 (必需)\n");
                    resultMessage.append(foundOutputTemplate ? "✓ 输出模板 - 已导入\n" : "✗ 输出模板 - 未导入 (必需)\n");
                    resultMessage.append(foundTaxData ? "✓ 个税表 - 已导入\n" : "✗ 个税表 - 未导入 (必需)\n");
                    resultMessage.append(foundSocialInsurance ? "✓ 社保表 - 已导入\n" : "✗ 社保表 - 未导入 (必需)\n");
                    resultMessage.append(foundMonthlyDeduction ? "✓ 扣款表 - 已导入\n" : "✗ 扣款表 - 未导入 (必需)\n");
                    resultMessage.append(foundProcessingGroup ? "✓ 加工组 - 已导入\n" : "✗ 加工组 - 未导入 (必需)\n");
                    resultMessage.append(foundAttendance ? "✓ 考勤表 - 已导入\n" : "✗ 考勤表 - 未导入 (必需)\n");
                    resultMessage.append(foundAssessmentScore ? "✓ 考核得分 - 已导入\n" : "✗ 考核得分 - 未导入 (必需)\n");
                    resultMessage.append(foundUtilityRent ? "✓ 水电租表 - 已导入\n" : "✗ 水电租表 - 未导入 (必需)\n");
                    resultMessage.append(foundCoefficientTable ? "✓ 系数表 - 已导入\n" : "✗ 系数表 - 未导入 (必需)\n"); // 新增
                    
                    // 自定义对话框，使其更易读
                    JTextArea textArea = new JTextArea(resultMessage.toString());
                    textArea.setEditable(false);
                    textArea.setFont(new Font("宋体", Font.PLAIN, 14));
                    textArea.setLineWrap(true);
                    textArea.setWrapStyleWord(true);
                    JScrollPane scrollPane = new JScrollPane(textArea);
                    scrollPane.setPreferredSize(new Dimension(600, 400));
                    
                    // 显示导入结果对话框
                    JOptionPane.showMessageDialog(SalaryCalculatorApp.this, 
                        scrollPane, "文件导入结果", JOptionPane.INFORMATION_MESSAGE);
                    
                    // 设置状态栏信息
                    if (hasRequiredFiles) {
                        lblStatus.setText("所有必需文件导入成功，可以计算工资");
                    } else {
                        lblStatus.setText("缺少必需文件，请确保导入所有10种表格后再计算工资"); // 修改
                    }
                }
            };
            
            worker.execute();
        }
    }

    /**
     * 分析无法识别的Excel文件，提供更多信息
     */
    private void analyzeUnidentifiedExcelFile(String filePath, String fileName, List<String> errorMessages) {
        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = WorkbookFactory.create(fis)) {
             
            StringBuilder sheetInfo = new StringBuilder();
            
            // 检查工作表名称
            int sheetCount = workbook.getNumberOfSheets();
            sheetInfo.append("包含").append(sheetCount).append("个工作表：");
            
            for (int i = 0; i < sheetCount; i++) {
                Sheet sheet = workbook.getSheetAt(i);
                String sheetName = sheet.getSheetName();
                sheetInfo.append("[").append(sheetName).append("] ");
                
                // 特殊情况检查 - 考核得分
                if (sheetName.contains("考核") || sheetName.contains("得分") || sheetName.contains("分数")) {
                    logger.info("文件" + fileName + "包含可能的考核得分工作表: " + sheetName);
                    
                    // 检查前5行，寻找姓名列和分数列
                    boolean foundNameCol = false;
                    boolean foundScoreCol = false;
                    
                    for (int rowIdx = 0; rowIdx <= 4; rowIdx++) {
                        Row headerRow = sheet.getRow(rowIdx);
                        if (headerRow == null) continue;
                        
                        for (int colIdx = 0; colIdx < headerRow.getLastCellNum(); colIdx++) {
                            Cell cell = headerRow.getCell(colIdx);
                            if (cell == null) continue;
                            
                            String value = cell.toString().trim();
                            if (value.contains("姓名")) {
                                foundNameCol = true;
                            } else if (value.contains("分数") || value.contains("得分") || value.contains("考核分")) {
                                foundScoreCol = true;
                            }
                        }
                    }
                    
                    if (foundNameCol && foundScoreCol) {
                        errorMessages.add("✗ 文件 " + fileName + " 可能是考核得分表，但文件名不符合规范。请将文件命名为\"考核得分.xlsx\"或\"考核得分.xls\"");
                        return;
                    }
                }
                
                // 特殊情况检查 - 加工组
                if (sheetName.contains("分切") || sheetName.contains("切纸") || sheetName.contains("卡板")) {
                    logger.info("文件" + fileName + "包含可能的加工组工作表: " + sheetName);
                    
                    // 查找"分切组"和"卡板工"两个工作表
                    boolean foundCuttingSheet = false;
                    boolean foundPalletSheet = false;
                    
                    for (int j = 0; j < sheetCount; j++) {
                        String name = workbook.getSheetAt(j).getSheetName();
                        if (name.contains("分切") || name.contains("切纸")) {
                            foundCuttingSheet = true;
                        } else if (name.contains("卡板")) {
                            foundPalletSheet = true;
                        }
                    }
                    
                    if (foundCuttingSheet || foundPalletSheet) {
                        String message = "✗ 文件 " + fileName + " 可能是加工组表格，";
                        if (foundCuttingSheet && foundPalletSheet) {
                            message += "包含分切组和卡板工工作表。";
                        } else if (foundCuttingSheet) {
                            message += "包含分切组工作表但缺少卡板工工作表。";
                        } else {
                            message += "包含卡板工工作表但缺少分切组工作表。";
                        }
                        message += "请将文件命名为\"加工组.xlsx\"或\"加工组.xls\"";
                        errorMessages.add(message);
                        return;
                    }
                }
            }
            
            // 特殊情况检查 - 水电租表
            Sheet dataSheet = workbook.getSheet("数据源");
            if (dataSheet != null) {
                // 查找表头中是否包含"姓名"、"水费"、"电费"等关键列
                Row headerRow = dataSheet.getRow(0);
                if (headerRow != null) {
                    boolean hasNameCol = false;
                    boolean hasWaterCol = false;
                    boolean hasElectricCol = false;
                    
                    for (int i = 0; i < headerRow.getLastCellNum(); i++) {
                        Cell cell = headerRow.getCell(i);
                        if (cell == null) continue;
                        
                        String value = cell.toString().trim();
                        if (value.contains("姓名")) {
                            hasNameCol = true;
                        } else if (value.contains("水费")) {
                            hasWaterCol = true;
                        } else if (value.contains("电费")) {
                            hasElectricCol = true;
                        }
                    }
                    
                    if (hasNameCol && (hasWaterCol || hasElectricCol)) {
                        errorMessages.add("✗ 文件 " + fileName + " 包含'数据源'工作表和水电费相关列，可能是水电租表。请将文件名改为包含'水电租'字样。");
                        return;
                    }
                }
            }
            
            // 检查第一个工作表的表头内容
            if (sheetCount > 0) {
                Sheet firstSheet = workbook.getSheetAt(0);
                StringBuilder headerInfo = new StringBuilder("第一个工作表的表头包含: ");
                boolean foundHeaders = false;
                
                // 检查前5行可能的表头内容
                for (int rowIdx = 0; rowIdx <= 4; rowIdx++) {
                    Row row = firstSheet.getRow(rowIdx);
                    if (row == null) continue;
                    
                    for (int colIdx = 0; colIdx < row.getLastCellNum(); colIdx++) {
                        Cell cell = row.getCell(colIdx);
                        if (cell == null) continue;
                        
                        String value = cell.toString().trim();
                        if (!value.isEmpty()) {
                            headerInfo.append("[").append(value).append("] ");
                            foundHeaders = true;
                        }
                    }
                    
                    if (foundHeaders) {
                        break;
                    }
                }
                
                // 添加工作表信息
                if (foundHeaders) {
                    errorMessages.add("✗ 无法识别文件 " + fileName + "。" + sheetInfo.toString() + "。" + headerInfo.toString() + 
                            "。请确保文件命名符合规范，可用名称包括: 出库列表、业务员工资资料、输出模板、个税表、社保表、扣款表、加工组、考勤表、考核得分、水电租表、系数表"); // 修改
                } else {
                    errorMessages.add("✗ 无法识别文件 " + fileName + "。" + sheetInfo.toString() + 
                            "。请确保文件命名符合规范，可用名称包括: 出库列表、业务员工资资料、输出模板、个税表、社保表、扣款表、加工组、考勤表、考核得分、水电租表、系数表"); // 修改
                }
            } else {
                errorMessages.add("✗ 无法识别文件 " + fileName + "，文件不包含任何工作表。");
            }
            
        } catch (Exception e) {
            logger.error("分析文件 " + fileName + " 内容时出错: " + e.getMessage(), e);
            errorMessages.add("✗ 无法识别文件 " + fileName + "，分析内容时出错: " + e.getMessage());
        }
    }
} 
